blob: 2b1252963535caa93432e3216625efedfdc36ac8 [file] [log] [blame]
David Pursehouse8898e2f2012-11-14 07:51:03 +09001#!/usr/bin/env python
Mike Frysingerf6013762019-06-13 02:30:51 -04002# -*- coding:utf-8 -*-
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07003
Mike Frysinger87fb5a12019-06-13 01:54:46 -04004"""Repo launcher.
5
6This is a standalone tool that people may copy to anywhere in their system.
7It is used to get an initial repo client checkout, and after that it runs the
8copy of repo in the checkout.
9"""
10
Mike Frysingerc92ce5c2019-06-13 01:14:23 -040011from __future__ import print_function
12
Mike Frysinger3ba716f2019-06-13 01:48:12 -040013import os
14import platform
15import subprocess
16import sys
17
18
19def exec_command(cmd):
20 """Execute |cmd| or return None on failure."""
21 try:
22 if platform.system() == 'Windows':
23 ret = subprocess.call(cmd)
24 sys.exit(ret)
25 else:
26 os.execvp(cmd[0], cmd)
27 except:
28 pass
29
30
31def check_python_version():
32 """Make sure the active Python version is recent enough."""
33 def reexec(prog):
34 exec_command([prog] + sys.argv)
35
36 MIN_PYTHON_VERSION = (3, 6)
37
38 ver = sys.version_info
39 major = ver.major
40 minor = ver.minor
41
42 # Abort on very old Python 2 versions.
43 if (major, minor) < (2, 7):
44 print('repo: error: Your Python version is too old. '
45 'Please use Python {}.{} or newer instead.'.format(
46 *MIN_PYTHON_VERSION), file=sys.stderr)
47 sys.exit(1)
48
49 # Try to re-exec the version specific Python 3 if needed.
50 if (major, minor) < MIN_PYTHON_VERSION:
51 # Python makes releases ~once a year, so try our min version +10 to help
52 # bridge the gap. This is the fallback anyways so perf isn't critical.
53 min_major, min_minor = MIN_PYTHON_VERSION
54 for inc in range(0, 10):
55 reexec('python{}.{}'.format(min_major, min_minor + inc))
56
57 # Try the generic Python 3 wrapper, but only if it's new enough. We don't
58 # want to go from (still supported) Python 2.7 to (unsupported) Python 3.5.
59 try:
60 proc = subprocess.Popen(
61 ['python3', '-c', 'import sys; '
62 'print(sys.version_info.major, sys.version_info.minor)'],
63 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
64 (output, _) = proc.communicate()
65 python3_ver = tuple(int(x) for x in output.decode('utf-8').split())
66 except (OSError, subprocess.CalledProcessError):
67 python3_ver = None
68
69 # The python3 version looks like it's new enough, so give it a try.
70 if python3_ver and python3_ver >= MIN_PYTHON_VERSION:
71 reexec('python3')
72
73 # We're still here, so diagnose things for the user.
74 if major < 3:
75 print('repo: warning: Python 2 is no longer supported; '
76 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION),
77 file=sys.stderr)
78 else:
79 print('repo: error: Python 3 version is too old; '
80 'Please use Python {}.{} or newer.'.format(*MIN_PYTHON_VERSION),
81 file=sys.stderr)
82 sys.exit(1)
83
84
85if __name__ == '__main__':
86 # TODO(vapier): Enable this on Windows once we have Python 3 issues fixed.
87 if platform.system() != 'Windows':
88 check_python_version()
89
90
Mark E. Hamilton4088eb42016-02-10 10:44:30 -070091# repo default configuration
92#
Mark E. Hamilton55536282016-02-03 15:49:43 -070093import os
94REPO_URL = os.environ.get('REPO_URL', None)
95if not REPO_URL:
96 REPO_URL = 'https://gerrit.googlesource.com/git-repo'
Mike Frysinger563f1a62020-02-05 23:52:07 -050097REPO_REV = os.environ.get('REPO_REV')
98if not REPO_REV:
99 REPO_REV = 'stable'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700100
101# Copyright (C) 2008 Google Inc.
102#
103# Licensed under the Apache License, Version 2.0 (the "License");
104# you may not use this file except in compliance with the License.
105# You may obtain a copy of the License at
106#
107# http://www.apache.org/licenses/LICENSE-2.0
108#
109# Unless required by applicable law or agreed to in writing, software
110# distributed under the License is distributed on an "AS IS" BASIS,
111# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
112# See the License for the specific language governing permissions and
113# limitations under the License.
114
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700115# increment this whenever we make important changes to this script
Mike Frysingeree451f02020-02-04 00:00:08 -0500116VERSION = (2, 0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700117
118# increment this if the MAINTAINER_KEYS block is modified
Mike Frysingerf5525fb2020-02-04 00:01:00 -0500119KEYRING_VERSION = (2, 0)
Mike Frysingere4433652016-09-13 18:06:07 -0400120
121# Each individual key entry is created by using:
122# gpg --armor --export keyid
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700123MAINTAINER_KEYS = """
124
125 Repo Maintainer <repo@android.kernel.org>
126-----BEGIN PGP PUBLIC KEY BLOCK-----
127Version: GnuPG v1.4.2.2 (GNU/Linux)
128
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
164=CMiZ
165-----END PGP PUBLIC KEY BLOCK-----
166"""
167
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700168GIT = 'git' # our git command
Mike Frysinger655aedd2020-02-04 00:02:18 -0500169MIN_GIT_VERSION = (2, 10, 2) # minimum supported git version
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700170repodir = '.repo' # name of repo's private directory
171S_repo = 'repo' # special repo repository
172S_manifests = 'manifests' # special manifest repository
173REPO_MAIN = S_repo + '/main.py' # main script
Simran Basi8ce50412015-08-28 14:25:44 -0700174GITC_CONFIG_FILE = '/gitc/.config'
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700175GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700176
177
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400178import collections
David Jamesbf79c662013-12-26 14:20:13 -0800179import errno
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700180import optparse
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700181import re
Mitchel Humpheryseb5acc92014-03-12 10:48:15 -0700182import shutil
Sarah Owens60798a32012-10-25 17:53:09 -0700183import stat
David Pursehouse59bbb582013-05-17 10:49:33 +0900184
185if sys.version_info[0] == 3:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700186 import urllib.request
187 import urllib.error
188else:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700189 import imp
David Pursehouse59bbb582013-05-17 10:49:33 +0900190 import urllib2
Sarah Owens1f7627f2012-10-31 09:21:55 -0700191 urllib = imp.new_module('urllib')
192 urllib.request = urllib2
193 urllib.error = urllib2
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700194
Conley Owens5e0ee142013-09-26 15:50:49 -0700195
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700196home_dot_repo = os.path.expanduser('~/.repoconfig')
197gpg_dir = os.path.join(home_dot_repo, 'gnupg')
198
199extra_args = []
200init_optparse = optparse.OptionParser(usage="repo init -u url [options]")
201
202# Logging
203group = init_optparse.add_option_group('Logging options')
204group.add_option('-q', '--quiet',
205 dest="quiet", action="store_true", default=False,
206 help="be quiet")
207
208# Manifest
209group = init_optparse.add_option_group('Manifest options')
210group.add_option('-u', '--manifest-url',
211 dest='manifest_url',
212 help='manifest repository location', metavar='URL')
213group.add_option('-b', '--manifest-branch',
214 dest='manifest_branch',
215 help='manifest branch or revision', metavar='REVISION')
216group.add_option('-m', '--manifest-name',
217 dest='manifest_name',
218 help='initial manifest file', metavar='NAME.xml')
Ereth McKnight-MacNeil12ee5442018-12-19 21:28:35 -0800219group.add_option('--current-branch',
Naseer Ahmedf4dda9a2016-12-01 18:49:54 -0500220 dest='current_branch_only', action='store_true',
221 help='fetch only current manifest branch from server')
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800222group.add_option('--mirror',
223 dest='mirror', action='store_true',
David Pursehouse3794a782012-11-15 06:17:30 +0900224 help='create a replica of the remote repositories '
225 'rather than a client working directory')
Shawn O. Pearce88443382010-10-08 10:02:09 +0200226group.add_option('--reference',
227 dest='reference',
228 help='location of mirror directory', metavar='DIR')
Nikolai Merinov09f0abb2018-10-19 15:07:05 +0500229group.add_option('--dissociate',
230 dest='dissociate', action='store_true',
231 help='dissociate from reference mirrors after clone')
Doug Anderson49cd59b2011-06-13 21:42:06 -0700232group.add_option('--depth', type='int', default=None,
233 dest='depth',
234 help='create a shallow clone with given depth; see git clone')
Xin Li745be2e2019-06-03 11:24:30 -0700235group.add_option('--partial-clone', action='store_true',
236 dest='partial_clone',
237 help='perform partial clone (https://git-scm.com/'
238 'docs/gitrepository-layout#_code_partialclone_code)')
239group.add_option('--clone-filter', action='store', default='blob:none',
240 dest='clone_filter',
241 help='filter for use with --partial-clone [default: %default]')
Julien Campergue335f5ef2013-10-16 11:02:35 +0200242group.add_option('--archive',
243 dest='archive', action='store_true',
244 help='checkout an archive instead of a git repository for '
245 'each project. See git archive.')
Martin Kellye4e94d22017-03-21 16:05:12 -0700246group.add_option('--submodules',
247 dest='submodules', action='store_true',
248 help='sync any submodules associated with the manifest repo')
Colin Cross5acde752012-03-28 20:15:45 -0700249group.add_option('-g', '--groups',
Conley Owens971de8e2012-04-16 10:36:08 -0700250 dest='groups', default='default',
David Holmer0a1c6a12012-11-14 19:19:00 -0500251 help='restrict manifest projects to ones with specified '
252 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
Colin Cross5acde752012-03-28 20:15:45 -0700253 metavar='GROUP')
Conley Owensd21720d2012-04-16 11:02:21 -0700254group.add_option('-p', '--platform',
255 dest='platform', default="auto",
Conley Owensc9129d92012-10-01 16:12:28 -0700256 help='restrict manifest projects to ones with a specified '
Conley Owensd21720d2012-04-16 11:02:21 -0700257 'platform group [auto|all|none|linux|darwin|...]',
258 metavar='PLATFORM')
Hu xiuyun9711a982015-12-11 11:16:41 +0800259group.add_option('--no-clone-bundle',
260 dest='no_clone_bundle', action='store_true',
261 help='disable use of /clone.bundle on HTTP/HTTPS')
Naseer Ahmedf4dda9a2016-12-01 18:49:54 -0500262group.add_option('--no-tags',
263 dest='no_tags', action='store_true',
264 help="don't fetch tags in the manifest")
Doug Anderson49cd59b2011-06-13 21:42:06 -0700265
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700266
267# Tool
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700268group = init_optparse.add_option_group('repo Version options')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700269group.add_option('--repo-url',
270 dest='repo_url',
Mike Frysinger563f1a62020-02-05 23:52:07 -0500271 help='repo repository location ($REPO_URL)', metavar='URL')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700272group.add_option('--repo-branch',
273 dest='repo_branch',
Mike Frysinger563f1a62020-02-05 23:52:07 -0500274 help='repo branch or revision ($REPO_REV)', metavar='REVISION')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700275group.add_option('--no-repo-verify',
276 dest='no_repo_verify', action='store_true',
277 help='do not verify repo source code')
278
Victor Boivie841be342011-04-05 11:31:10 +0200279# Other
280group = init_optparse.add_option_group('Other options')
281group.add_option('--config-name',
282 dest='config_name', action="store_true", default=False,
283 help='Always prompt for name/e-mail')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700284
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700285
286def _GitcInitOptions(init_optparse_arg):
287 init_optparse_arg.set_usage("repo gitc-init -u url -c client [options]")
288 g = init_optparse_arg.add_option_group('GITC options')
Simran Basi1efc2b42015-08-05 15:04:22 -0700289 g.add_option('-f', '--manifest-file',
290 dest='manifest_file',
291 help='Optional manifest file to use for this GITC client.')
292 g.add_option('-c', '--gitc-client',
293 dest='gitc_client',
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700294 help='The name of the gitc_client instance to create or modify.')
Simran Basi1efc2b42015-08-05 15:04:22 -0700295
Simran Basi8ce50412015-08-28 14:25:44 -0700296_gitc_manifest_dir = None
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700297
298
Simran Basi8ce50412015-08-28 14:25:44 -0700299def get_gitc_manifest_dir():
300 global _gitc_manifest_dir
301 if _gitc_manifest_dir is None:
Dan Willemsen2487cb72015-08-31 15:45:06 -0700302 _gitc_manifest_dir = ''
Simran Basi8ce50412015-08-28 14:25:44 -0700303 try:
304 with open(GITC_CONFIG_FILE, 'r') as gitc_config:
305 for line in gitc_config:
306 match = re.match('gitc_dir=(?P<gitc_manifest_dir>.*)', line)
307 if match:
308 _gitc_manifest_dir = match.group('gitc_manifest_dir')
309 except IOError:
Dan Willemsen2487cb72015-08-31 15:45:06 -0700310 pass
Simran Basi8ce50412015-08-28 14:25:44 -0700311 return _gitc_manifest_dir
312
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700313
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700314def gitc_parse_clientdir(gitc_fs_path):
315 """Parse a path in the GITC FS and return its client name.
316
317 @param gitc_fs_path: A subdirectory path within the GITC_FS_ROOT_DIR.
318
319 @returns: The GITC client name
320 """
321 if gitc_fs_path == GITC_FS_ROOT_DIR:
322 return None
323 if not gitc_fs_path.startswith(GITC_FS_ROOT_DIR):
324 manifest_dir = get_gitc_manifest_dir()
325 if manifest_dir == '':
326 return None
327 if manifest_dir[-1] != '/':
328 manifest_dir += '/'
329 if gitc_fs_path == manifest_dir:
330 return None
331 if not gitc_fs_path.startswith(manifest_dir):
332 return None
333 return gitc_fs_path.split(manifest_dir)[1].split('/')[0]
334 return gitc_fs_path.split(GITC_FS_ROOT_DIR)[1].split('/')[0]
335
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700336
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700337class CloneFailure(Exception):
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700338
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700339 """Indicate the remote clone of repo itself failed.
340 """
341
342
Simran Basi1efc2b42015-08-05 15:04:22 -0700343def _Init(args, gitc_init=False):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700344 """Installs repo by cloning it over the network.
345 """
Simran Basi1efc2b42015-08-05 15:04:22 -0700346 if gitc_init:
347 _GitcInitOptions(init_optparse)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700348 opt, args = init_optparse.parse_args(args)
Xiaodong Xuae0a36c2012-01-31 11:10:09 +0800349 if args:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700350 init_optparse.print_usage()
351 sys.exit(1)
352
353 url = opt.repo_url
354 if not url:
355 url = REPO_URL
356 extra_args.append('--repo-url=%s' % url)
357
358 branch = opt.repo_branch
359 if not branch:
360 branch = REPO_REV
361 extra_args.append('--repo-branch=%s' % branch)
362
363 if branch.startswith('refs/heads/'):
364 branch = branch[len('refs/heads/'):]
365 if branch.startswith('refs/'):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400366 print("fatal: invalid branch name '%s'" % branch, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700367 raise CloneFailure()
368
David Jamesbf79c662013-12-26 14:20:13 -0800369 try:
Simran Basi1efc2b42015-08-05 15:04:22 -0700370 if gitc_init:
Simran Basi8ce50412015-08-28 14:25:44 -0700371 gitc_manifest_dir = get_gitc_manifest_dir()
372 if not gitc_manifest_dir:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400373 print('fatal: GITC filesystem is not available. Exiting...',
374 file=sys.stderr)
Simran Basi8ce50412015-08-28 14:25:44 -0700375 sys.exit(1)
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700376 gitc_client = opt.gitc_client
377 if not gitc_client:
378 gitc_client = gitc_parse_clientdir(os.getcwd())
379 if not gitc_client:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400380 print('fatal: GITC client (-c) is required.', file=sys.stderr)
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700381 sys.exit(1)
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700382 client_dir = os.path.join(gitc_manifest_dir, gitc_client)
Simran Basi1efc2b42015-08-05 15:04:22 -0700383 if not os.path.exists(client_dir):
384 os.makedirs(client_dir)
385 os.chdir(client_dir)
386 if os.path.exists(repodir):
387 # This GITC Client has already initialized repo so continue.
388 return
389
David Jamesbf79c662013-12-26 14:20:13 -0800390 os.mkdir(repodir)
391 except OSError as e:
392 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400393 print('fatal: cannot make %s directory: %s'
394 % (repodir, e.strerror), file=sys.stderr)
David Pursehouse3794a782012-11-15 06:17:30 +0900395 # Don't raise CloneFailure; that would delete the
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700396 # name. Instead exit immediately.
397 #
398 sys.exit(1)
399
400 _CheckGitVersion()
401 try:
Sebastian Schuberth8f997b32020-01-20 11:42:48 +0100402 if opt.no_repo_verify:
403 do_verify = False
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700404 else:
Sebastian Schuberth8f997b32020-01-20 11:42:48 +0100405 if NeedSetupGnuPG():
406 do_verify = SetupGnuPG(opt.quiet)
407 else:
408 do_verify = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700409
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700410 dst = os.path.abspath(os.path.join(repodir, S_repo))
Hu xiuyun9711a982015-12-11 11:16:41 +0800411 _Clone(url, dst, opt.quiet, not opt.no_clone_bundle)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700412
Sebastian Schuberth8f997b32020-01-20 11:42:48 +0100413 if do_verify:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700414 rev = _Verify(dst, branch, opt.quiet)
415 else:
416 rev = 'refs/remotes/origin/%s^0' % branch
417
418 _Checkout(dst, branch, rev, opt.quiet)
Sebastian Schuberth993dcac2018-07-13 10:25:52 +0200419
420 if not os.path.isfile(os.path.join(dst, 'repo')):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400421 print("warning: '%s' does not look like a git-repo repository, is "
422 "REPO_URL set correctly?" % url, file=sys.stderr)
Sebastian Schuberth993dcac2018-07-13 10:25:52 +0200423
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700424 except CloneFailure:
425 if opt.quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400426 print('fatal: repo init failed; run without --quiet to see why',
427 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700428 raise
429
430
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400431# The git version info broken down into components for easy analysis.
432# Similar to Python's sys.version_info.
433GitVersion = collections.namedtuple(
434 'GitVersion', ('major', 'minor', 'micro', 'full'))
435
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400436def ParseGitVersion(ver_str=None):
437 if ver_str is None:
438 # Load the version ourselves.
439 ver_str = _GetGitVersion()
440
Conley Owensff0a3c82014-01-30 14:46:03 -0800441 if not ver_str.startswith('git version '):
442 return None
443
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400444 full_version = ver_str[len('git version '):].strip()
445 num_ver_str = full_version.split('-')[0]
Conley Owensff0a3c82014-01-30 14:46:03 -0800446 to_tuple = []
447 for num_str in num_ver_str.split('.')[:3]:
448 if num_str.isdigit():
449 to_tuple.append(int(num_str))
450 else:
451 to_tuple.append(0)
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400452 to_tuple.append(full_version)
453 return GitVersion(*to_tuple)
Conley Owensff0a3c82014-01-30 14:46:03 -0800454
455
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400456def _GetGitVersion():
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700457 cmd = [GIT, '--version']
Shawn O. Pearce4fd38ec2012-06-05 07:55:07 -0700458 try:
459 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700460 except OSError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400461 print(file=sys.stderr)
462 print("fatal: '%s' is not available" % GIT, file=sys.stderr)
463 print('fatal: %s' % e, file=sys.stderr)
464 print(file=sys.stderr)
465 print('Please make sure %s is installed and in your path.' % GIT,
466 file=sys.stderr)
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400467 raise
Shawn O. Pearce4fd38ec2012-06-05 07:55:07 -0700468
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700469 ver_str = proc.stdout.read().strip()
470 proc.stdout.close()
Shawn O. Pearce16191342008-10-28 08:33:34 -0700471 proc.wait()
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400472 return ver_str.decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700473
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400474
475def _CheckGitVersion():
476 try:
477 ver_act = ParseGitVersion()
478 except OSError:
479 raise CloneFailure()
480
Conley Owensff0a3c82014-01-30 14:46:03 -0800481 if ver_act is None:
Mike Frysinger4c263b52019-09-11 04:04:16 -0400482 print('fatal: unable to detect git version', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700483 raise CloneFailure()
484
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700485 if ver_act < MIN_GIT_VERSION:
David Pursehouse685f0802012-11-14 08:34:39 +0900486 need = '.'.join(map(str, MIN_GIT_VERSION))
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400487 print('fatal: git %s or later required' % need, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700488 raise CloneFailure()
489
490
Conley Owensc9129d92012-10-01 16:12:28 -0700491def NeedSetupGnuPG():
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700492 if not os.path.isdir(home_dot_repo):
493 return True
494
495 kv = os.path.join(home_dot_repo, 'keyring-version')
496 if not os.path.exists(kv):
497 return True
498
499 kv = open(kv).read()
500 if not kv:
501 return True
502
David Pursehouse685f0802012-11-14 08:34:39 +0900503 kv = tuple(map(int, kv.split('.')))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700504 if kv < KEYRING_VERSION:
505 return True
506 return False
507
508
Conley Owensc9129d92012-10-01 16:12:28 -0700509def SetupGnuPG(quiet):
David Jamesbf79c662013-12-26 14:20:13 -0800510 try:
511 os.mkdir(home_dot_repo)
512 except OSError as e:
513 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400514 print('fatal: cannot make %s directory: %s'
515 % (home_dot_repo, e.strerror), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700516 sys.exit(1)
517
David Jamesbf79c662013-12-26 14:20:13 -0800518 try:
519 os.mkdir(gpg_dir, stat.S_IRWXU)
520 except OSError as e:
521 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400522 print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror),
523 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700524 sys.exit(1)
525
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800526 env = os.environ.copy()
Dāvis Mosāns631d0ec2016-07-16 21:11:11 +0300527 try:
528 env['GNUPGHOME'] = gpg_dir
529 except UnicodeEncodeError:
530 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700531
532 cmd = ['gpg', '--import']
533 try:
534 proc = subprocess.Popen(cmd,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700535 env=env,
536 stdin=subprocess.PIPE)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700537 except OSError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700538 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400539 print('warning: gpg (GnuPG) is not available.', file=sys.stderr)
540 print('warning: Installing it is strongly encouraged.', file=sys.stderr)
541 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700542 return False
543
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400544 proc.stdin.write(MAINTAINER_KEYS.encode('utf-8'))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700545 proc.stdin.close()
546
547 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400548 print('fatal: registering repo maintainer keys failed', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700549 sys.exit(1)
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400550 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700551
Mike Frysinger3164d402019-11-11 05:40:22 -0500552 with open(os.path.join(home_dot_repo, 'keyring-version'), 'w') as fd:
553 fd.write('.'.join(map(str, KEYRING_VERSION)) + '\n')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700554 return True
555
556
557def _SetConfig(local, name, value):
558 """Set a git configuration option to the specified value.
559 """
560 cmd = [GIT, 'config', name, value]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700561 if subprocess.Popen(cmd, cwd=local).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700562 raise CloneFailure()
563
564
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700565def _InitHttp():
566 handlers = []
567
Sarah Owens1f7627f2012-10-31 09:21:55 -0700568 mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700569 try:
570 import netrc
571 n = netrc.netrc()
572 for host in n.hosts:
573 p = n.hosts[host]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700574 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
Xiaodong Xuae0a36c2012-01-31 11:10:09 +0800575 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
David Pursehouse65b0ba52018-06-24 16:21:51 +0900576 except:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700577 pass
Sarah Owens1f7627f2012-10-31 09:21:55 -0700578 handlers.append(urllib.request.HTTPBasicAuthHandler(mgr))
579 handlers.append(urllib.request.HTTPDigestAuthHandler(mgr))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700580
581 if 'http_proxy' in os.environ:
582 url = os.environ['http_proxy']
Sarah Owens1f7627f2012-10-31 09:21:55 -0700583 handlers.append(urllib.request.ProxyHandler({'http': url, 'https': url}))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700584 if 'REPO_CURL_VERBOSE' in os.environ:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700585 handlers.append(urllib.request.HTTPHandler(debuglevel=1))
586 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
587 urllib.request.install_opener(urllib.request.build_opener(*handlers))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700588
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700589
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700590def _Fetch(url, local, src, quiet):
591 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400592 print('Get %s' % url, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700593
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700594 cmd = [GIT, 'fetch']
595 if quiet:
596 cmd.append('--quiet')
597 err = subprocess.PIPE
598 else:
599 err = None
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700600 cmd.append(src)
601 cmd.append('+refs/heads/*:refs/remotes/origin/*')
Xin Li6e538442018-12-10 11:33:16 -0800602 cmd.append('+refs/tags/*:refs/tags/*')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700603
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700604 proc = subprocess.Popen(cmd, cwd=local, stderr=err)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700605 if err:
606 proc.stderr.read()
607 proc.stderr.close()
608 if proc.wait() != 0:
609 raise CloneFailure()
610
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700611
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700612def _DownloadBundle(url, local, quiet):
613 if not url.endswith('/'):
614 url += '/'
615 url += 'clone.bundle'
616
617 proc = subprocess.Popen(
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700618 [GIT, 'config', '--get-regexp', 'url.*.insteadof'],
619 cwd=local,
620 stdout=subprocess.PIPE)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700621 for line in proc.stdout:
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400622 line = line.decode('utf-8')
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700623 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
624 if m:
625 new_url = m.group(1)
626 old_url = m.group(2)
627 if url.startswith(old_url):
628 url = new_url + url[len(old_url):]
629 break
630 proc.stdout.close()
631 proc.wait()
632
633 if not url.startswith('http:') and not url.startswith('https:'):
634 return False
635
636 dest = open(os.path.join(local, '.git', 'clone.bundle'), 'w+b')
637 try:
638 try:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700639 r = urllib.request.urlopen(url)
640 except urllib.error.HTTPError as e:
John Törnblomd3ddcdb2015-08-12 20:12:51 +0200641 if e.code in [401, 403, 404, 501]:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700642 return False
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400643 print('fatal: Cannot get %s' % url, file=sys.stderr)
644 print('fatal: HTTP error %s' % e.code, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700645 raise CloneFailure()
Sarah Owens1f7627f2012-10-31 09:21:55 -0700646 except urllib.error.URLError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400647 print('fatal: Cannot get %s' % url, file=sys.stderr)
648 print('fatal: error %s' % e.reason, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700649 raise CloneFailure()
650 try:
651 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400652 print('Get %s' % url, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700653 while True:
654 buf = r.read(8192)
Mike Frysinger1b9adab2019-07-04 17:54:54 -0400655 if not buf:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700656 return True
657 dest.write(buf)
658 finally:
659 r.close()
660 finally:
661 dest.close()
662
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700663
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700664def _ImportBundle(local):
665 path = os.path.join(local, '.git', 'clone.bundle')
666 try:
667 _Fetch(local, local, path, True)
668 finally:
669 os.remove(path)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700670
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700671
Hu xiuyun9711a982015-12-11 11:16:41 +0800672def _Clone(url, local, quiet, clone_bundle):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700673 """Clones a git repository to a new subdirectory of repodir
674 """
675 try:
676 os.mkdir(local)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700677 except OSError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400678 print('fatal: cannot make %s directory: %s' % (local, e.strerror),
679 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700680 raise CloneFailure()
681
682 cmd = [GIT, 'init', '--quiet']
683 try:
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700684 proc = subprocess.Popen(cmd, cwd=local)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700685 except OSError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400686 print(file=sys.stderr)
687 print("fatal: '%s' is not available" % GIT, file=sys.stderr)
688 print('fatal: %s' % e, file=sys.stderr)
689 print(file=sys.stderr)
690 print('Please make sure %s is installed and in your path.' % GIT,
691 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700692 raise CloneFailure()
693 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400694 print('fatal: could not create %s' % local, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700695 raise CloneFailure()
696
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700697 _InitHttp()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700698 _SetConfig(local, 'remote.origin.url', url)
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700699 _SetConfig(local,
700 'remote.origin.fetch',
701 '+refs/heads/*:refs/remotes/origin/*')
Hu xiuyun9711a982015-12-11 11:16:41 +0800702 if clone_bundle and _DownloadBundle(url, local, quiet):
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700703 _ImportBundle(local)
Dan Willemsenfee390e2015-09-02 12:36:30 -0700704 _Fetch(url, local, 'origin', quiet)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700705
706
707def _Verify(cwd, branch, quiet):
708 """Verify the branch has been signed by a tag.
709 """
710 cmd = [GIT, 'describe', 'origin/%s' % branch]
711 proc = subprocess.Popen(cmd,
712 stdout=subprocess.PIPE,
713 stderr=subprocess.PIPE,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700714 cwd=cwd)
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400715 cur = proc.stdout.read().strip().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700716 proc.stdout.close()
717
718 proc.stderr.read()
719 proc.stderr.close()
720
721 if proc.wait() != 0 or not cur:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400722 print(file=sys.stderr)
723 print("fatal: branch '%s' has not been signed" % branch, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700724 raise CloneFailure()
725
726 m = re.compile(r'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur)
727 if m:
728 cur = m.group(1)
729 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400730 print(file=sys.stderr)
731 print("info: Ignoring branch '%s'; using tagged release '%s'"
732 % (branch, cur), file=sys.stderr)
733 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700734
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800735 env = os.environ.copy()
Dāvis Mosāns631d0ec2016-07-16 21:11:11 +0300736 try:
737 env['GNUPGHOME'] = gpg_dir
738 except UnicodeEncodeError:
739 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700740
741 cmd = [GIT, 'tag', '-v', cur]
742 proc = subprocess.Popen(cmd,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700743 stdout=subprocess.PIPE,
744 stderr=subprocess.PIPE,
745 cwd=cwd,
746 env=env)
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400747 out = proc.stdout.read().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700748 proc.stdout.close()
749
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400750 err = proc.stderr.read().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700751 proc.stderr.close()
752
753 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400754 print(file=sys.stderr)
755 print(out, file=sys.stderr)
756 print(err, file=sys.stderr)
757 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700758 raise CloneFailure()
759 return '%s^0' % cur
760
761
762def _Checkout(cwd, branch, rev, quiet):
763 """Checkout an upstream branch into the repository and track it.
764 """
765 cmd = [GIT, 'update-ref', 'refs/heads/default', rev]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700766 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700767 raise CloneFailure()
768
769 _SetConfig(cwd, 'branch.default.remote', 'origin')
770 _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch)
771
772 cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default']
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700773 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700774 raise CloneFailure()
775
776 cmd = [GIT, 'read-tree', '--reset', '-u']
777 if not quiet:
778 cmd.append('-v')
779 cmd.append('HEAD')
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700780 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700781 raise CloneFailure()
782
783
784def _FindRepo():
785 """Look for a repo installation, starting at the current directory.
786 """
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200787 curdir = os.getcwd()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700788 repo = None
789
Anthony Newnamdf14a702011-01-09 17:31:57 -0800790 olddir = None
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200791 while curdir != '/' \
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700792 and curdir != olddir \
793 and not repo:
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200794 repo = os.path.join(curdir, repodir, REPO_MAIN)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700795 if not os.path.isfile(repo):
796 repo = None
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200797 olddir = curdir
798 curdir = os.path.dirname(curdir)
799 return (repo, os.path.join(curdir, repodir))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700800
801
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700802class _Options(object):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700803 help = False
804
805
806def _ParseArguments(args):
807 cmd = None
808 opt = _Options()
809 arg = []
810
Sarah Owensa6053d52012-11-01 13:36:50 -0700811 for i in range(len(args)):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700812 a = args[i]
813 if a == '-h' or a == '--help':
814 opt.help = True
815
816 elif not a.startswith('-'):
817 cmd = a
818 arg = args[i + 1:]
819 break
820 return cmd, opt, arg
821
822
823def _Usage():
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700824 gitc_usage = ""
825 if get_gitc_manifest_dir():
826 gitc_usage = " gitc-init Initialize a GITC Client.\n"
827
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400828 print(
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700829 """usage: repo COMMAND [ARGS]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700830
831repo is not yet installed. Use "repo init" to install it here.
832
833The most commonly used repo commands are:
834
835 init Install repo in the current working directory
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700836""" + gitc_usage +
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700837 """ help Display detailed help on a command
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700838
839For access to the full online help, install repo ("repo init").
Mike Frysinger35159ab2019-06-13 00:07:13 -0400840""")
841 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700842
843
844def _Help(args):
845 if args:
846 if args[0] == 'init':
847 init_optparse.print_help()
Trond Norbyed3fd5372011-01-03 11:35:15 +0100848 sys.exit(0)
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700849 elif args[0] == 'gitc-init':
850 _GitcInitOptions(init_optparse)
851 init_optparse.print_help()
852 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700853 else:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400854 print("error: '%s' is not a bootstrap command.\n"
855 ' For access to online help, install repo ("repo init").'
856 % args[0], file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700857 else:
858 _Usage()
859 sys.exit(1)
860
861
862def _NotInstalled():
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400863 print('error: repo is not installed. Use "repo init" to install it here.',
864 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700865 sys.exit(1)
866
867
868def _NoCommands(cmd):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400869 print("""error: command '%s' requires repo to be installed first.
870 Use "repo init" to install it here.""" % cmd, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700871 sys.exit(1)
872
873
874def _RunSelf(wrapper_path):
875 my_dir = os.path.dirname(wrapper_path)
876 my_main = os.path.join(my_dir, 'main.py')
877 my_git = os.path.join(my_dir, '.git')
878
879 if os.path.isfile(my_main) and os.path.isdir(my_git):
Shawn O. Pearcec8a300f2009-05-18 13:19:57 -0700880 for name in ['git_config.py',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700881 'project.py',
882 'subcmds']:
883 if not os.path.exists(os.path.join(my_dir, name)):
884 return None, None
885 return my_main, my_git
886 return None, None
887
888
889def _SetDefaultsTo(gitdir):
890 global REPO_URL
891 global REPO_REV
892
893 REPO_URL = gitdir
894 proc = subprocess.Popen([GIT,
895 '--git-dir=%s' % gitdir,
896 'symbolic-ref',
897 'HEAD'],
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700898 stdout=subprocess.PIPE,
899 stderr=subprocess.PIPE)
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400900 REPO_REV = proc.stdout.read().strip().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700901 proc.stdout.close()
902
903 proc.stderr.read()
904 proc.stderr.close()
905
906 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400907 print('fatal: %s has no current branch' % gitdir, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700908 sys.exit(1)
909
910
911def main(orig_args):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700912 cmd, opt, args = _ParseArguments(orig_args)
913
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700914 repo_main, rel_repo_dir = None, None
915 # Don't use the local repo copy, make sure to switch to the gitc client first.
916 if cmd != 'gitc-init':
917 repo_main, rel_repo_dir = _FindRepo()
918
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700919 wrapper_path = os.path.abspath(__file__)
920 my_main, my_git = _RunSelf(wrapper_path)
921
Simran Basi8ce50412015-08-28 14:25:44 -0700922 cwd = os.getcwd()
Dan Willemsen2487cb72015-08-31 15:45:06 -0700923 if get_gitc_manifest_dir() and cwd.startswith(get_gitc_manifest_dir()):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400924 print('error: repo cannot be used in the GITC local manifest directory.'
925 '\nIf you want to work on this GITC client please rerun this '
926 'command from the corresponding client under /gitc/',
927 file=sys.stderr)
Simran Basi8ce50412015-08-28 14:25:44 -0700928 sys.exit(1)
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200929 if not repo_main:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700930 if opt.help:
931 _Usage()
932 if cmd == 'help':
933 _Help(args)
934 if not cmd:
935 _NotInstalled()
Simran Basi1efc2b42015-08-05 15:04:22 -0700936 if cmd == 'init' or cmd == 'gitc-init':
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700937 if my_git:
938 _SetDefaultsTo(my_git)
939 try:
Simran Basi1efc2b42015-08-05 15:04:22 -0700940 _Init(args, gitc_init=(cmd == 'gitc-init'))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700941 except CloneFailure:
Sebastian Schuberth27226e72016-10-28 14:27:43 +0200942 path = os.path.join(repodir, S_repo)
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400943 print("fatal: cloning the git-repo repository failed, will remove "
944 "'%s' " % path, file=sys.stderr)
Sebastian Schuberth27226e72016-10-28 14:27:43 +0200945 shutil.rmtree(path, ignore_errors=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700946 sys.exit(1)
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200947 repo_main, rel_repo_dir = _FindRepo()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700948 else:
949 _NoCommands(cmd)
950
951 if my_main:
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200952 repo_main = my_main
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700953
David Pursehouse685f0802012-11-14 08:34:39 +0900954 ver_str = '.'.join(map(str, VERSION))
anatoly techtonik3a2a59e2013-09-21 19:29:10 +0300955 me = [sys.executable, repo_main,
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200956 '--repo-dir=%s' % rel_repo_dir,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700957 '--wrapper-version=%s' % ver_str,
958 '--wrapper-path=%s' % wrapper_path,
959 '--']
960 me.extend(orig_args)
961 me.extend(extra_args)
Mike Frysinger3ba716f2019-06-13 01:48:12 -0400962 exec_command(me)
963 print("fatal: unable to start %s" % repo_main, file=sys.stderr)
964 sys.exit(148)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700965
966
967if __name__ == '__main__':
968 main(sys.argv[1:])